# frozen_string_literal: true

require "react_on_rails/utils"

module ReactOnRailsPro
  class Cache
    class << self
      # options[:cache_options] can include :compress, :expires_in, :race_condition_ttl and
      # other options
      def fetch_react_component(component_name, options)
        if use_cache?(options)
          cache_key = react_component_cache_key(component_name, options)
          Rails.logger.debug { "React on Rails Pro cache_key is #{cache_key.inspect}" }
          cache_options = options[:cache_options]
          cache_hit = true
          result = Rails.cache.fetch(cache_key, cache_options) do
            cache_hit = false
            yield
          end
          # Pass back the cache key in the results only if the result is a Hash
          if result.is_a?(Hash)
            result[:RORP_CACHE_KEY] = cache_key
            result[:RORP_CACHE_HIT] = cache_hit
          end
          result
        else
          yield
        end
      end

      def use_cache?(options)
        if options.key?(:if)
          options[:if]
        elsif options.key?(:unless)
          !options[:unless]
        else
          true
        end
      end

      # Cache keys by React on Rails Pro should build upon this base
      # Provide prerender: true in order to include bundle hash in the list of keys.
      # The bundle hash is necessary so that any changes to the bundle fault the cache.
      def base_cache_key(type, prerender: nil)
        keys = [
          type,
          ReactOnRails::VERSION,
          ReactOnRailsPro::VERSION
        ]

        # TODO: Move comment over to test
        # We only care about the bundle hash if prerendering because we're not caching anything
        # that would be generated by the bundle.
        keys.push(ReactOnRailsPro::Utils.bundle_hash) if prerender
        keys
      end

      def dependencies_cache_key
        # https://github.com/shakacode/react_on_rails_pro/issues/32
        # https://github.com/shakacode/react_on_rails/issues/39#issuecomment-143472325
        return @dependency_checksum if @dependency_checksum.present? && !Rails.env.development?
        return nil unless ReactOnRailsPro.configuration.dependency_globs.present?

        @dependency_checksum =
          ReactOnRailsPro::Utils.digest_of_globs(
            ReactOnRailsPro.configuration.dependency_globs
          ).hexdigest
      end

      def react_component_cache_key(component_name, options)
        cache_key_option = options[:cache_key]
        cache_key_value = if cache_key_option.respond_to?(:call)
                            cache_key_option.call
                          else
                            cache_key_option
                          end

        # NOTE: Rails seems to do this automatically: ActiveSupport::Cache.expand_cache_key(keys)
        [
          *base_cache_key("ror_component", prerender: options[:prerender]),
          dependencies_cache_key,
          component_name,
          cache_key_value
        ].compact
      end
    end
  end
end
